home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
IRIS Performer 2.2 Friends Demo
/
SGI IRIS Performer 2.2 Friends Demo.iso
/
friends
/
medit
/
pfLoader
/
Internalstuff
/
engines.c
< prev
next >
Wrap
Text File
|
1997-11-20
|
12KB
|
497 lines
/************************************************************************
Extract information from a bezier (see your text book!)
************************************************************************/
#define BezierPosition(axis) ((b0*p0[axis]) + (b1*p1[axis]) + (b2*p2[axis]) + (b3*p3[axis]))
#define BezierVelocity(axis) ((b0*(p1[axis]-p0[axis])) + (b1*(p2[axis]-p1[axis])) + (b2*(p3[axis]-p2[axis])))
#define BezierAcceleration(axis) ((b0*(p0[axis]+p2[axis]-(2*p1[axis]))) + (b1*(p1[axis]+p3[axis]-(2*p2[axis]))))
#define BezierAccelAccel(axis) ( b0*((p3[axis]-p0[axis]) + (b1*(p1[axis]-p2[axis]))))
void BezierCalc(reg BezierDataPtr b, reg real t, reg int request, reg real (*result)[XYZ])
{
reg real b0, b1, b2, b3;
reg real *p0, *p1, *p2, *p3;
reg real t1, t2, t3, t12, t13;
t2 = t*t; /* Powers of t and (1-t) */
t3 = t2*t;
t1 = 1.0-t;
t12 = t1*t1;
t13 = t12*t1;
p0 = b->ControlPoint[0];
p1 = b->ControlPoint[1];
p2 = b->ControlPoint[2];
p3 = b->ControlPoint[3];
if (request & BPosition) {
b0 = t13;
b1 = 3.0*t*t12;
b2 = 3.0*t2*t1;
b3 = t3;
result[0][X] = BezierPosition(X);
result[0][Y] = BezierPosition(Y);
result[0][Z] = BezierPosition(Z);
result++;
}
if (request & BVelocity) {
b0 = 3.0*t12;
b1 = 6.0*t*t1;
b2 = 3.0*t2;
result[0][X] = BezierVelocity(X);
result[0][Y] = BezierVelocity(Y);
result[0][Z] = BezierVelocity(Z);
result++;
}
if (request & BAcceleration) {
b0 = -6.0*t1;
b1 = 6.0*t;
result[0][X] = BezierAcceleration(X);
result[0][Y] = BezierAcceleration(Y);
result[0][Z] = BezierAcceleration(Z);
result++;
}
if (request & BAccelAccel) {
b0 = 6.0;
b1 = 3.0;
result[0][X] = BezierAccelAccel(X);
result[0][Y] = BezierAccelAccel(Y);
result[0][Z] = BezierAccelAccel(Z);
}
}
/************************************************************************
Convert distance along a path to bezier/t
************************************************************************/
static boolean ChopMotionData(reg PathPtr p, reg real distance, reg BezierDataPtr *bezier, reg real *t)
{
reg BezierDataPtr s;
reg int i, j, m, last, count;
reg real start, end, length, segsize;
if (p) {
#if ITSTHEMODELLER
if (!p->Valid OR !p->NoCurves OR !p->Curve) {
GenerateBezierData(p);
}
#endif
if (!p->NoCurves OR !p->Curve) {
return FALSE;
}
if (distance < 0) {
*bezier = p->Curve;
*t = 0;
return TRUE;
}
else if (distance > p->CurveLength) {
*bezier = p->Curve+(p->NoCurves-1);
*t = 1.0;
return TRUE;
}
i = 0; /* Binary chop the list of bezier subcurves */
j = p->NoCurves;
count = 0;
until (TheCowsAreHome) {
count++;
m = (i+j)>>1;
s = p->Curve+m;
start = s->Start;
length = s->Length;
end = start + length;
if (distance < start) {
j = m;
}
else if (distance > end) {
if (i IS m) { /* Avoid infinite loop when ((j-i) IS 1) */
i = j;
}
else {
i = m;
}
}
else {
break;
}
}
*bezier = s;
if (!s->l) {
return FALSE;
}
i = 0; /* Then binary chop the parameterisation */
j = s->Subdivision;
last = j-1;
distance -= start;
until (TheCowsAreHome) {
count++;
m = (i+j)>>1;
start = s->l[m];
if (m IS last) {
length = s->Length - start;
}
else {
length = s->l[m+1] - start;
}
end = start + length;
if (distance < start) {
j = m;
}
else if (distance > end) {
if (i IS m) {
i = m = j;
}
else {
i = m;
}
}
else {
break;
}
}
segsize = 1.0/s->Subdivision;
*t = ((real)m * segsize) + (((distance-start)/length) * segsize);
return TRUE;
}
return FALSE;
}
/************************************************************************
The data passed around during the engine updates
************************************************************************/
typedef struct EngineCalcStruct {
real Value; /* Value to output */
real StartTime; /* Time reference */
/* Parameters for bezier calcs */
real t;
PathPtr path;
BezierDataPtr bezier;
flag HasBezier;
} EngineCalc;
typedef EngineCalc *EngineCalcPtr;
static void InitEngineCalc(reg EngineCalcPtr e)
{
e->Value = 0.0;
e->StartTime = 0.0;
e->HasBezier = FALSE;
}
/************************************************************************
Initialise an engine at the start
************************************************************************/
static void EngineInitialiser(rconst TreePtr t, rconst void *start)
{
reg TreePtr c;
t->Active = t->StartActive;
t->StartTime = *(real*)start;
switch (t->Type) {
case AngleEngine: t->Angle = t->Offset;
break;
case DcsOutput: c = t->Connection;
if (c) {
c->OutputX = c->OutputBX =
c->OutputY = c->OutputBY =
c->OutputZ = c->OutputBZ =
c->OutputH = c->OutputBH =
c->OutputP = c->OutputBP =
c->OutputR = c->OutputBR = FALSE;
}
break;
}
}
/************************************************************************
Update engines
************************************************************************/
#define CopyEngineCalc(dest, src) memcpy(dest, src, sizeof(EngineCalc))
#define ResetE if (!FirstOne) { CopyEngineCalc(e, &start); FirstOne = FALSE; }
#define DoOutput(output, what) \
if (t->output) { \
c->output = TRUE; \
c->DcsValue.what = e->Value;\
}
static void EngineUpdater(reg TreePtr t, reg EngineCalcPtr e)
{
EngineCalc start;
reg PathPtr p;
reg TreePtr c, recurse;
reg real angle, distance;
reg flag FirstOne = TRUE, DontRecurse;
CopyEngineCalc(&start, e);
while (t) {
if (t->Active) {
DontRecurse = FALSE;
switch (t->Type) {
case TimeEngine: ResetE;
e->Value = ElapsedTime - e->StartTime;
break;
case LineEngine: ResetE;
e->Value = ((ElapsedTime-t->StartTime)*t->Scale) + t->Offset;
break;
case AngleEngine: ResetE;
if (t->StartTime ISNT ElapsedTime) {
t->Angle += FrameTime*t->Scale;
while (t->Angle > 360.0) {
t->Angle -= 360.0;
}
while (t->Angle < -360.0) {
t->Angle += 360.0;
}
t->StartTime = ElapsedTime;
}
e->Value = t->Angle;
break;
case WaveEngine: ResetE;
angle = (t->NoWaves * (ElapsedTime/t->WaveTime)) + t->Offset;
e->Value = sin((angle*(2.0*M_PI))+rad(t->Phase)) * t->Scale;
break;
case SensorEngine: ResetE;
break;
case ScalarEngine: e->Value = (e->Value * t->Scale) + t->Offset;
ResetE;
break;
case SplineEngine: ResetE;
p = t->PathData;
distance = e->Value;
if (p->Closed) {
distance = fmod(distance, p->CurveLength);
}
if (ChopMotionData(p, distance, &(e->bezier), &(e->t))) {
e->HasBezier = TRUE;
e->path = t->PathData;
}
break;
case CompareEngine: ResetE;
if (t->CompareType IS 0) {
DontRecurse = (e->Value <= t->Scale);
}
else {
DontRecurse = (e->Value >= t->Scale);
}
break;
case DcsOutput: c = t->Connection;
if (c) {
ResetE;
if (e->HasBezier) {
c->t = e->t;
c->path = e->path;
c->bezier = e->bezier;
c->OutputBX = t->OutputX;
c->OutputBY = t->OutputY;
c->OutputBZ = t->OutputZ;
c->OutputBH = t->OutputH;
c->OutputBP = t->OutputP;
c->OutputBR = t->OutputR;
}
else {
DoOutput(OutputX, x);
DoOutput(OutputY, y);
DoOutput(OutputZ, z);
DoOutput(OutputH, h);
DoOutput(OutputP, p);
DoOutput(OutputR, r);
}
}
break;
case SwitchOutput: c = t->Connection;
if (c) {
c->Visible = t->SwitchOn;
}
break;
case ActivatorEngine: c = t->Connection;
if (c) {
c->Active = TRUE;
c->StartTime = ElapsedTime;
}
break;
case DeactivatorEngine: c = t->Connection;
if (c) {
c->Active = FALSE;
}
break;
}
if (!DontRecurse) {
recurse = t->Across;
if (recurse) {
EngineUpdater(recurse, e);
}
}
}
t = t->Down;
}
}
/************************************************************************
Generate a DCS matrix
************************************************************************/
#if ITSTHEMODELLER
/* Bridge the from Performer to ModelWorks internal routines */
#define pfArcTan2(y, x) deg(atan2f(y, x))
#define SinCos(a, s, c) { s = sinf(rad(a)); c = cosf(rad(a)); }
#else
/* ditto ModelWorks to Performer */
#define SmallMatrix pfMatrix
#define SmallMatrixPtr pfMatrix
#define MultSmallMatrix(a, b, dst) pfMultMat(dst, a, b)
#define IdentifySmall(m) pfMakeIdentMat(m)
#define CopySmallMatrix(dst, src) pfCopyMat(dst, src)
#define PreTranslateSmall(m, x, y, z) pfPreTransMat(m, x, y, z, m);
#define PreYawSmall(m, a) pfPreRotMat(m, a, 0, 0, 1, m);
#define PrePitchSmall(m, a) pfPreRotMat(m, a, 1, 0, 0, m);
#define PreRollSmall(m, a) pfPreRotMat(m, a, 0, 1, 0, m);
#define SinCos(a, s, c) pfSinCos(a, &s, &c);
static
#endif
void CalcPitchAndHeading(float v[XYZ], float *pitch, float *heading)
{
float sinh, cosh;
reg float h, x, y;
x = v[X]; y = v[Y];
if ((x IS 0.0) AND (y IS 0.0)) {
*pitch = 90;
*heading = 0;
}
else {
h = *heading = pfArcTan2(y, x);
SinCos(-h, sinh, cosh);
x = (x*cosh) - (y*sinh);
*pitch = -pfArcTan2(v[Z], x);
}
}
boolean MakeDcsMatrix(reg TreePtr Dcs, reg SmallMatrixPtr m)
{
reg real *c;
real bv[4][3];
reg PathPtr path;
reg float x, y, z;
float h, p, ph[3];
reg BezierDataPtr bezier;
reg flag DoXYZ, DoHPR, DoBXYZ, DoBHPR, hold;
reg flag ox, oy, oz, oh, op, or, obx, oby, obz, obh, obp, obr;
ox = Dcs->OutputX; oy = Dcs->OutputY; oz = Dcs->OutputZ;
oh = Dcs->OutputH; op = Dcs->OutputP; or = Dcs->OutputR;
DoXYZ = ox OR oy OR oz;
DoHPR = oh OR op OR or;
obx = Dcs->OutputBX; oby = Dcs->OutputBY; obz = Dcs->OutputBZ;
obh = Dcs->OutputBH; obp = Dcs->OutputBP; obr = Dcs->OutputBR;
DoBXYZ = obx OR oby OR obz;
DoBHPR = obh OR obp OR obr;
hold = Dcs->HoldValues;
if (DoXYZ OR DoHPR OR DoBXYZ OR DoBHPR) {
if (DoBXYZ OR DoBHPR) {
#if ITSTHEMODELLER
IdentifySmall(m);
#else
CopySmallMatrix(m, Dcs->DcsInverse);
#endif
path = Dcs->path;
bezier = Dcs->bezier;
c = path->Curve[0].ControlPoint[0];
BezierCalc(bezier, Dcs->t, BPosition|BVelocity, bv);
if (DoBXYZ) {
x = y = z = 0.0;
if (obx) {
if (!hold) Dcs->OutputBX = FALSE;
x = bv[0][X]-c[X];
}
if (oby) {
if (!hold) Dcs->OutputBY = FALSE;
y = bv[0][Y]-c[Y];
}
if (obz) {
if (!hold) Dcs->OutputBZ = FALSE;
z = bv[0][Z]-c[Z];
}
PreTranslateSmall(m, x, y, z);
}
if (DoBHPR) {
c = path->Curve[0].ControlPoint[0];
PreTranslateSmall(m, c[X], c[Y], c[Z]);
CopyXYZ(ph, bv[1]);
CalcPitchAndHeading(ph, &p, &h);
if (obh) {
if (!hold) Dcs->OutputBH = FALSE;
PreYawSmall(m, h-path->HeadingOffset);
}
if (obp) {
if (!hold) Dcs->OutputBP = FALSE;
PrePitchSmall(m, p-path->PitchOffset);
}
PreTranslateSmall(m, -c[X], -c[Y], -c[Z]);
}
MultSmallMatrix(Dcs->DcsSmall, m, m);
}
else {
#if ITSTHEMODELLER
CopySmallMatrix(m, Dcs->DcsSmall);
#else
pfMakeIdentMat(m);
#endif
}
if (DoXYZ) {
x = y = z = 0.0;
if (ox) {
if (!hold) Dcs->OutputX = FALSE;
x = Dcs->DcsValue.x;
}
if (oy) {
if (!hold) Dcs->OutputY = FALSE;
y = Dcs->DcsValue.y;
}
if (oz) {
if (!hold) Dcs->OutputZ = FALSE;
z = Dcs->DcsValue.z;
}
PreTranslateSmall(m, x, y, z);
}
if (DoHPR) {
if (oh) {
if (!hold) Dcs->OutputH = FALSE;
PreYawSmall(m, Dcs->DcsValue.h);
}
if (op) {
if (!hold) Dcs->OutputP = FALSE;
PrePitchSmall(m, Dcs->DcsValue.p);
}
if (or) {
if (!hold) Dcs->OutputR = FALSE;
PreRollSmall(m, Dcs->DcsValue.r);
}
}
#if ITSTHEMODELLER
MultSmallMatrix(Dcs->DcsInverse, m, m);
#endif
return TRUE;
}
IdentifySmall(m);
return FALSE;
}